package androidextras.builder;

import java.awt.List;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import java.util.regex.Pattern;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

public class AndroidExtrasBuilder extends IncrementalProjectBuilder {

	class AndroidExtrasDeltaVisitor implements IResourceDeltaVisitor {
		private IProject project;

		public AndroidExtrasDeltaVisitor(IProject project) {
			this.project = project;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse
		 * .core.resources.IResourceDelta)
		 */
		public boolean visit(IResourceDelta delta) throws CoreException {
			IResource resource = delta.getResource();
			switch (delta.getKind()) {
			case IResourceDelta.ADDED:
				// handle added resource
				if (resource instanceof IFile) {
					FileUtils.flatten((IFile) resource, project);
				}
				break;
			case IResourceDelta.REMOVED:
				// handle removed resource
				if (resource instanceof IFile) {
					FileUtils.delete((IFile) resource, project);
				}
				break;
			case IResourceDelta.CHANGED:
				// handle changed resource
				if (resource instanceof IFile) {
					FileUtils.flatten((IFile) resource, project);
				}
				break;
			}
			// return true to continue visiting children.
			return true;
		}
	}

	class AndroidExtrasResourceVisitor implements IResourceVisitor {
		private IProject project;
		private ArrayList<String> resources = new ArrayList<String>();
		private ArrayList<String> references = new ArrayList<String>();
		private Pattern patternR;

		public AndroidExtrasResourceVisitor(IProject project) {
			this.project = project;
			patternR = Pattern.compile("R\\p{Punct}[a-z]*\\p{Punct}[a-z_]*");
		}

		public ArrayList<String> getUnusedResources() {
			for(int i=0;i<references.size();i++){
				for(int j=0;j<resources.size();j++){
				if(resources.get(j).equals(references.get(i))){
					resources.remove(j);
				}
				}
			}
			return resources;
		}

		public boolean visit(IResource resource) {
			if (resource instanceof IFile) {
				if (resource.getFullPath().toString().contains("res")) {
					int dot = Math.max(resource.getFullPath().toString()
							.lastIndexOf("\\"), resource.getFullPath()
							.toString().lastIndexOf("/"));
					dot = Math.max(resource.getFullPath().toString()
							.lastIndexOf("\\", dot - 1), resource.getFullPath()
							.toString().lastIndexOf("/", dot - 1));
					String res = dot != -1 ? resource.getFullPath().toString()
							.substring(
									dot + 1,
									resource.getFullPath().toString()
											.lastIndexOf(".")).replace("\\",
									".").replace("/", ".") : resource.getName();
					resources.add(res);
				}
				FileUtils.flatten((IFile) resource, project);
				if (resource.getFullPath().toString().endsWith("xml")) {

				}
				if (resource.getFullPath().toString().endsWith("java")) {
					File file = resource.getRawLocation().toFile();
					try {
						DataInputStream stream = new DataInputStream(
								new BufferedInputStream(new FileInputStream(
										file)));
						while (true) {
							String line = stream.readLine();
							if (line == null)
								break;
							String[] matcher = patternR.split(line);
							int index;
							for (int i = 0; i < matcher.length - 1; i++) {
								index = line.indexOf(matcher[i + 1]);
								String res = line.substring(
										matcher[i].length(), index);
								res = res.substring(res.indexOf(".") + 1);
								references.add(res);
							}
						}
					} catch (FileNotFoundException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
			// return true to continue visiting children.
			return true;
		}
	}

	class XMLErrorHandler extends DefaultHandler {

		private IFile file;

		public XMLErrorHandler(IFile file) {
			this.file = file;
		}

		private void addMarker(SAXParseException e, int severity) {
			AndroidExtrasBuilder.this.addMarker(file, e.getMessage(), e
					.getLineNumber(), severity);
		}

		public void error(SAXParseException exception) throws SAXException {
			addMarker(exception, IMarker.SEVERITY_ERROR);
		}

		public void fatalError(SAXParseException exception) throws SAXException {
			addMarker(exception, IMarker.SEVERITY_ERROR);
		}

		public void warning(SAXParseException exception) throws SAXException {
			addMarker(exception, IMarker.SEVERITY_WARNING);
		}
	}

	public static final String BUILDER_ID = "AndroidExtras.sampleBuilder";

	private static final String MARKER_TYPE = "AndroidExtras.xmlProblem";

	private SAXParserFactory parserFactory;

	private void addMarker(IFile file, String message, int lineNumber,
			int severity) {
		try {
			IMarker marker = file.createMarker(MARKER_TYPE);
			marker.setAttribute(IMarker.MESSAGE, message);
			marker.setAttribute(IMarker.SEVERITY, severity);
			if (lineNumber == -1) {
				lineNumber = 1;
			}
			marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
		} catch (CoreException e) {
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.core.internal.events.InternalBuilder#build(int,
	 * java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
	 */
	protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
			throws CoreException {
		IFolder folder = getProject().getFolder("res");
		if (!folder.exists())
			folder.create(true, true, null);
		if (kind == FULL_BUILD) {
			fullBuild(monitor);
		} else {
			IResourceDelta delta = getDelta(getProject());
			if (delta == null) {
				fullBuild(monitor);
			} else {
				incrementalBuild(delta, monitor);
			}
		}
		return null;
	}

	void checkXML(IResource resource) {
		if (resource instanceof IFile && resource.getName().endsWith(".xml")) {
			IFile file = (IFile) resource;
			deleteMarkers(file);
			XMLErrorHandler reporter = new XMLErrorHandler(file);
			try {
				getParser().parse(file.getContents(), reporter);
			} catch (Exception e1) {
			}
		}
	}

	private void deleteMarkers(IFile file) {
		try {
			file.deleteMarkers(MARKER_TYPE, false, IResource.DEPTH_ZERO);
		} catch (CoreException ce) {
		}
	}

	protected void fullBuild(final IProgressMonitor monitor)
			throws CoreException {
		try {
			AndroidExtrasResourceVisitor androidExtrasResourceVisitor = new AndroidExtrasResourceVisitor(getProject());
			getProject().accept(androidExtrasResourceVisitor,
					IResource.DEPTH_INFINITE, false);
			ArrayList<String> unusedResources = androidExtrasResourceVisitor.getUnusedResources();
			for(int i=0;i<unusedResources.size();i++){
				System.err.println("resource "+unusedResources.get(i)+" is probably unused");
			}
		} catch (CoreException e) {
		}
	}

	private SAXParser getParser() throws ParserConfigurationException,
			SAXException {
		if (parserFactory == null) {
			parserFactory = SAXParserFactory.newInstance();
		}
		return parserFactory.newSAXParser();
	}

	protected void incrementalBuild(IResourceDelta delta,
			IProgressMonitor monitor) throws CoreException {
		// the visitor does the work.
		delta.accept(new AndroidExtrasDeltaVisitor(getProject()));
	}
}
